package MyRedis

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"time"
)

const (
	Serilizer_Json = "json"
	Serilizer_Gob  = "gob"
)

type DbGetterFunc func() interface{}

/**
SimpleCache  缓存基础结构
*/
type SimpleCache struct {
	Operation *StringOperation //操作类
	Expire    time.Duration    //过期时间
	DbGetter  DbGetterFunc     //一旦缓存中没有  DB获取的方法
	Serilizer string           //序列化方法
	Policy    CachePolicy      //缓存策略
}

func NewSimpleCache(operation *StringOperation, expire time.Duration, serilize string, policy CachePolicy) *SimpleCache {
	//将操作类丢入缓存策略 主要用于 当返回nil时设置空缓存
	policy.SetOperation(operation)
	return &SimpleCache{Operation: operation, Expire: expire, Serilizer: serilize, Policy: policy}
}

/**
SetCache 设置缓存
*/
func (c *SimpleCache) SetCache(key string, val interface{}) {
	c.Operation.Set(key, val, WithExpire(c.Expire)).Unwrap()
}

/**
GetCacheForObject 获取缓存写入obj
*/
func (c *SimpleCache) GetCacheForObject(key string, val interface{}) interface{} {
	//获取缓存
	ret := c.GetCache(key)
	if ret == nil {
		return nil
	}
	//判断序列化方式
	if c.Serilizer == Serilizer_Json {
		//将json 序列化 写入val
		err := json.Unmarshal([]byte(ret.(string)), val)
		if err != nil {
			return nil
		}
	} else if c.Serilizer == Serilizer_Gob {
		//将gob 通过buf 写入val
		var buf = &bytes.Buffer{}
		buf.WriteString(ret.(string))
		dec := gob.NewDecoder(buf)
		if dec.Decode(val) != nil {
			return nil
		}
	}
	return nil
}

/**
GetCache 获取缓存
*/
func (c *SimpleCache) GetCache(key string) (ret interface{}) {
	if c.Policy != nil {
		//缓存key过滤
		c.Policy.Before(key)
	}
	//判断序列化方式
	//传入 函数 当获取缓存出现错误时
	//通过DbGetter 获取数据
	//并通过对应的 序列化方式 转化数据
	if c.Serilizer == Serilizer_Json {
		f := func() string {
			obj := c.DbGetter()
			b, err := json.Marshal(obj)
			if err != nil {
				return ""
			}
			return string(b)
		}
		ret = c.Operation.Get(key).UnwrapFunc(f)
	} else if c.Serilizer == Serilizer_Gob {
		f := func() string {
			obj := c.DbGetter()
			if obj == nil {
				return ""
			}
			var buf = &bytes.Buffer{}
			enc := gob.NewEncoder(buf)
			if err := enc.Encode(obj); err != nil {
				return ""
			}
			return buf.String()
		}
		ret = c.Operation.Get(key).UnwrapFunc(f)
	}
	//当返回数据为空时 且缓存策略存在 设置空缓存
	if ret.(string) == "" && c.Policy != nil {
		c.Policy.IfNil(key, "")
	} else {
		c.SetCache(key, ret)
	}
	return
}
